//============================================================================
// Name        : Tarea4EspinozaTiznado.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C, Ansi-style
//============================================================================
#include "glob.h"
//#include "IO.h"
#include "Hebra.h"





char *baseDatosName = NULL;
char *consultasName = NULL;
char *insertarName = NULL;
char *eliminarName = NULL;
char *baseDatosActualizadaName = NULL;
char *salidaName = NULL;

pthread_mutex_t	candado = PTHREAD_MUTEX_INITIALIZER;

info* datos;


/*
  info* dato = (info*)arg;
  printf( "Hebra OK=%d de N=%d\n", dato->tid, dato->n_threads );

  dato->n = 0;
  dato->m = dato->largo_arreglo / (dato->tid+1);

  dato->x = (int*)malloc(sizeof(int)*10);
  for( int i = 0; i < 10; i++ )
    dato->x[i] = i;

  printf( "Hebra OK=%d de N=%d\n", dato->tid, dato->n_threads );
  //(*dato).tid
  return NULL;*/

void *Consultar(void* arg)
{
	info* temp = (info*)arg;
	temp->consultas;

	for(int i=0;i<temp->consultasSize;i++)
	{
		std::vector<int> local=temp->consultas[i];
		pthread_mutex_lock(&candado);
		if(local.size()==1)
		{

			std::vector linea=local.at(0);

			for(std::vector<int>::iterator iter = linea.begin();iter !=linea.end();iter++)
			{
				temp->salida[i].insert(*iter);
			}
		}
		pthread_mutex_unlock(&candado);
	}

	return NULL;

}

void* Eliminar(void* arg)
{
	/*info* temp = (info*) arg;
	std::vector<int> porEliminar = (std::vector<int>)arg;


	pthread_mutex_lock(&candado);

	for(unsigned int i=0;i<porEliminar.size;i++)
		{
			std::cout << " Eliminar=" << i << " archivos:"<<temp->eliminar[i].size()<< std::endl;
			std::vector<int> temp = temp->eliminar[i];

			for(std::vector<int>::iterator iter = temp.begin();iter !=temp.end();iter++)
			{
				std::cout <<  *iter << " ";
			}
			std::cout<<std::endl;
		}

	pthread_mutex_unlock(&candado);*/
	return NULL;
}

void* InsertarValores()
{
	return NULL;
}



long ContarLineas( const char* _file)
{
	long filesize = 0;
	ifstream fin;
	fin.open( _file );
	if( !fin.is_open( ) )
	{
		cout << "ERROR: no se pudo abrir archivo de base de datos:" << _file << endl;
		exit( -1 );
	}
	string line;
	while( getline( fin, line ) )
	{
		filesize++;
	}
	return filesize;
}

bool CargarBase( const char* _file)
{
	ifstream fin;
	fin.open( _file );
	if( !fin.is_open( ) )
	{
		cout << "ERROR: no se pudo abrir archivo de base de datos:" << _file << endl;
		return false;
	}
	datos->baseSize=ContarLineas(_file);
	datos->baseDatos=new vector<int>[datos->baseSize];

	string line;
	int linenumber=0;
	while( getline( fin, line ) )
	{
		//imprimir bases de datos
		cout << "Base " << line << endl;

		stringstream tmp( line );

		//int vez=0;
		while( tmp.good( ) )
		{
			//cout<< "vez "<<vez<<endl;
			string t;
			tmp >> t;
			//if(vez>0)
				datos->baseDatos[linenumber].push_back(atoi( t.c_str( ) ));
			//vez++;
		}
		linenumber++;
	}
	fin.close();
	return true;
}

bool CargarConsultas( const char* _file)
{
	ifstream fin;
	fin.open( _file );
	if( !fin.is_open( ) )
	{
		cout << "ERROR: no se pudo abrir archivo de base de datos:" << _file << endl;
		return false;
	}
	datos->consultasSize=ContarLineas(_file);
	cout<< "linas "<< datos->consultasSize << endl;
	datos->consultas=new vector<int>[datos->consultasSize];
	datos->salida=new set<int>[datos->consultasSize];

	string line;
	int linenumber=0;
	while( getline( fin, line ) )
	{
		//imprimir bases de datos
		cout << "Consulta " << line << endl;

		stringstream tmp( line );

		while( tmp.good( ) )
		{
			//cout<< "vez "<<vez<<endl;
			string t;
			tmp >> t;
			datos->consultas[linenumber].push_back(atoi( t.c_str( ) ));
		}
		linenumber++;
	}
	fin.close();
	return true;
}

bool CargarEliminar( const char* _file)
{
	ifstream fin;
	fin.open( _file );
	if( !fin.is_open( ) )
	{
		cout << "ERROR: no se pudo abrir archivo de base de datos:" << _file << endl;
		return false;
	}
	datos->eliminarSize=ContarLineas(_file);
	datos->eliminar=new vector<int>[datos->eliminarSize];

	string line;
	int linenumber=0;
	while( getline( fin, line ) )
	{
		//imprimir bases de datos
		//cout << "Eliminar " << line << endl;

		stringstream tmp( line );

		while( tmp.good( ) )
		{
			string t;
			tmp >> t;
			datos->eliminar[linenumber].push_back(atoi( t.c_str( ) ));
		}
		linenumber++;
	}
	fin.close();
	return true;
}

bool CargarInsertar( const char* _file)
{
	ifstream fin;
	fin.open( _file );
	if( !fin.is_open( ) )
	{
		cout << "ERROR: no se pudo abrir archivo de base de datos:" << _file << endl;
		return false;
	}
	datos->insertarSize=ContarLineas(_file);
	datos->insertar=new vector<int>[datos->insertarSize];

	string line;
	int linenumber=0;
	while( getline( fin, line ) )
	{
		//imprimir bases de datos
		//cout << "Insertar " << line << endl;

		stringstream tmp( line );

		while( tmp.good( ) )
		{
			string t;
			tmp >> t;
			datos->insertar[linenumber].push_back(atoi( t.c_str( ) ));
		}
		linenumber++;
	}
	fin.close();
	return true;
}


void EscribirSalida( const char* _filename)
{
	ofstream outfile (_filename,ofstream::binary);

	cout<<"Base actualizada"<<endl;

	for(unsigned int i=0;i<datos->salida->size()-1;i++)
	{
		set<int> temp = datos->salida[i];
		outfile <<i <<" ";
		cout <<i <<" ";
		for(set<int>::iterator iter = temp.begin();iter !=temp.end();iter++)
		{
			cout <<  *iter << " ";
			outfile <<  *iter << " ";
		}
		cout<<endl;
		outfile<<endl;
	}
	outfile.close();
}

void EscribirBaseActualizada( const char* _filename)
{
	ofstream outfile (_filename,ofstream::binary);

	cout<<"Base actualizada"<<endl;

	for(unsigned int i=0;i<datos->baseDatos->size()-1;i++)
	{
		//cout << " Linea=" << i << " elems:"<<baseDatos[i].size();

		vector<int> temp = datos->baseDatos[i];
		outfile <<i <<" ";
		cout <<i <<" ";
		for(vector<int>::iterator iter = temp.begin();iter !=temp.end();iter++)
		{
			cout <<  *iter << " ";
			outfile <<  *iter << " ";
		}
		cout<<endl;
		outfile<<endl;
	}
	outfile.close();
}

int main (int argc, char **argv)
{
    int bflag = 0;
    int cflag = 0;
	int iflag = 0;
	int eflag = 0;
    int oflag = 0;
	int aflag = 0;

    int index;
    int c;

    errno =0;

    opterr = 0;

    while ((c = getopt (argc, argv, "b:c:i:e:o:a:")) != -1)
    {
		switch (c)
		{
			case 'b':
				bflag = 1;
				baseDatosName=optarg;
				cout << "Argumento Base de Datos: " << baseDatosName << endl;
				break;
			case 'c':
				cflag = 1;
				consultasName = optarg;
				cout << "Argumento Hilos: " << consultasName << endl;
				break;
			case 'i':
				iflag = 1;
				insertarName=optarg;
				cout << "Argumento Insertar: " << insertarName << endl;
				break;
			case 'e':
				eflag = 1;
				eliminarName=optarg;
				cout << "Argumento Editar: " << eliminarName << endl;
				break;
			case 'o':
				oflag = 1;
				salidaName=optarg;
				cout << "Argumento Output: " << salidaName << endl;
				break;
			case 'a':
				aflag=1;
				baseDatosActualizadaName=optarg;
				cout << "Argumento Base Actualizada: " << baseDatosActualizadaName << endl;
				break;
			case '?':
				if (optopt == 'c')
					fprintf (stderr, "Option -%c requires an argument.\n", optopt);
				else
					if (isprint (optopt))
						fprintf (stderr, "Unknown option `-%c'.\n", optopt);
					else
						fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt);
					return 1;
			default:
				cout << "Error Argumento consultas: "<<optarg<< endl;
				abort ();
		}
    }

    if((bflag*cflag*iflag*eflag*oflag*aflag==0))
    {
		cout<<"No se entregaron todos los parametros."<<endl;
		return EXIT_FAILURE;
    }


    for (index = optind; index < argc; index++)
		printf ("Non-option argument %s\n", argv[index]);

    /**CargarBase de Datos**/


    cout<< "Lineas BD: "<< ContarLineas(baseDatosName) << endl;

    if(CargarBase(baseDatosName))
    {
    	for(unsigned int i=0;i<datos->baseDatos->size()-1;i++)
		{
			cout << " Linea=" << i << " elems:"<<datos->baseDatos[i].size();
			vector<int> temp = datos->baseDatos[i];

			for(vector<int>::iterator iter = temp.begin();iter !=temp.end();iter++)
			{
				cout <<  *iter << " ";
			}
			cout<<endl;
		}
    }
    else
    	cout<< "Mal" << endl;

    cout<< "Lineas Consulta: "<< ContarLineas(consultasName) << endl;

    if(CargarConsultas(consultasName))
	{
    	//cout<< "archivo Consulta: "<< datos->consultas->size() << endl;
		/*for(unsigned int i=0;i<=datos->consultas->size();i++)
		{
			cout << " Consulta=" << i << " archivos:"<<datos->consultas[i].size()<< endl;
			vector<int> temp = datos->consultas[i];

			for(vector<int>::iterator iter = temp.begin();iter !=temp.end();iter++)
			{
				cout <<  *iter << " ";
			}
			cout<<endl;
		}*/



	}
	else
		cout<< "Error Lectura Consultas" << endl;

    //cout<< "Lineas Eliminar: "<< ContarLineas(eliminarName) << endl;

	if(CargarEliminar(eliminarName))
	{
		/*cout<< "archivo Eliminar: "<< datos->eliminar->size() << endl;
		for(unsigned int i=0;i<eliminarSize;i++)
		{
			cout << " Eliminar=" << i << " archivos:"<<datos->eliminar[i].size()<< endl;
			vector<int> temp = datos->eliminar[i];

			for(vector<int>::iterator iter = temp.begin();iter !=temp.end();iter++)
			{
				cout <<  *iter << " ";
			}
			cout<<endl;
		}*/


	}
	else
		cout<< "Error Lectura Eliminar" << endl;

	//cout<< "Lineas Insertar: "<< ContarLineas(insertarName) << endl;
	if(CargarInsertar(insertarName))
		{
			for(unsigned int i=0;i<datos->insertarSize;i++)
			{
				cout << " Insertar " << i << " archivos:"<<datos->insertar[i].size()<< endl;
				vector<int> temp = datos->insertar[i];

				for(vector<int>::iterator iter = temp.begin();iter !=temp.end();iter++)
				{
					cout <<  *iter << " ";
				}
				cout<<endl;
			}
		}
		else
			cout<< "Error Lectura Insertar" << endl;

	//llamar a hebras

	//info* info;
	//fo->

	pthread_t tc,te,tid;

	//Hebra* hebra = new Hebra();


	int errc = pthread_create( &tc,NULL,&Consultar,(void *)&datos);

	if( errc != 0 )
	      printf("No se pudo crear hebra:[%s]", strerror(errc));
	    else
	      printf("Hebra creada OK\n" );

	int erre = pthread_create( &te,NULL,&Eliminar,(void *)&datos);

	if( erre != 0 )
	      printf("No se pudo crear hebra:[%s]", strerror(erre));
	    else
	      printf("Hebra creada OK\n");

	/*int erri = pthread_create(&tid, NULL ,(void*)&InsertarValores,(void *)&datos);

	if( erri != 0 )
	      printf("No se pudo crear hebra:[%s]", strerror(erri));
	    else
	      printf("Hebra creada OK:\n");*/

	pthread_join( tc,NULL );
	pthread_join( te,NULL );
	//pthread_join( tid,NULL );


		/** Duda **/
	//Punteros a punteros y evitar copiar mas de una vez la memoria compartida
	



	//impresion salida
	
	EscribirSalida(salidaName);

	//generacion BBDD actualizada

    EscribirBaseActualizada(baseDatosActualizadaName);

    return EXIT_SUCCESS;
}
